package com.gemframework.core;

import com.gemframework.common.GemException;
import com.gemframework.util.PortUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.env.RandomValuePropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.util.StringUtils;

import java.util.Arrays;

/**
 * Accord to {@link RandomValuePropertySource}
 */
public class ServerPortSelectorPropertySource extends PropertySource {

    private static final Log logger = LogFactory.getLog(ServerPortSelectorPropertySource.class);

    private static final String PROPERTY_SOURCE_NAME = "port";
    private static final String PREFIX = "port.";

    public ServerPortSelectorPropertySource() {
        this(PROPERTY_SOURCE_NAME);
    }

    public ServerPortSelectorPropertySource(String name) {
        super(name);
    }

    @Override
    public Object getProperty(String name) {
        if (!name.startsWith(PREFIX)) {
            return null;
        }
        if (logger.isTraceEnabled()) {
            logger.trace("Generating server port property for '" + name + "'");
        }

        String range = getRange(name.substring(PREFIX.length()));
        String[] ports = StringUtils.commaDelimitedListToStringArray(range);

        return Arrays.stream(ports)
                .parallel()
                .map(StringUtils::trimWhitespace)
                .filter(port -> !StringUtils.isEmpty(port))
                .map(Integer::parseInt)
                .filter(PortUtil::isAvailable)
                .findAny()
                .orElseThrow(() -> new GemException("Available server port is not found!"));
    }

    private String getRange(String type) {
        String prefix = "in";
        if (type.startsWith(prefix)) {
            int startIndex = prefix.length() + 1;
            if (type.length() > startIndex) {
                return type.substring(startIndex, type.length() - 1);
            }
        }
        return null;
    }
}